using System;
using System.Security.Principal;
using System.Security.Permissions;
using System.Runtime.InteropServices;

namespace OrbitOne.SharePoint.Provision.WebParts
{
    /// <summary>
    /// This class allows your code to elevate its privledge by suspending the impersonation
    /// of the current logon user and reverting to the identity of the process account (this is
    /// basically the RunAs account that is assigned to the AppPool that hosts this process).
    ///
    /// It is often desirable to suspend impersonation when you need to have your code execute
    /// administrative-level functions for which the current logon user may not have permission.
    /// Based on http://www.sharepointu.com/forums/Impersonation_problem_in_Sharepoint_2007/m_44262/tm.htm
    /// </summary>
    public class ElevationManager : IDisposable
    {
        // This member caches the identity of the current logon user while impersonation is
        // suspended; we'll restore this identity when we resume impersonation.
        //
        private WindowsIdentity impersonatedUserIdentity = null;

        public ElevationManager()
        {
            SuspendImpersonation();
        }

        /// <summary>
        /// Releases all resources reserved by this object. When control returns from this method,
        /// the current thread will be running under the identity of the current logon user.
        /// </summary>
        public void Dispose()
        {
            ResumeImpersonation();
        }

        /// <summary>
        /// Suspends impersonation on the thread. When control returns from this method, the
        /// current thread will be running under the identity of the AppPool RunAs account.
        /// </summary>
        public void SuspendImpersonation()
        {
            // Fetch the identity associated with the Thread.
            impersonatedUserIdentity = WindowsIdentity.GetCurrent();

            // If this is the System account, there isn't any work to do.
            if (impersonatedUserIdentity.IsSystem)
            {
                return;
            }

            if (!Win32API.RevertToSelf())
            {
                throw new System.Security.SecurityException();
            }

            // <hack>
            // At this point, we ask the process to impersonate the the AppPool RunAs account.
            // This configures Thread and Context objects with the information necessary to please
            // the various If this impersonation does not occur, any
            // subsequent object model operations never complete successfully.
            // </hack>
           
            WindowsImpersonationContext impersonatedUser = WindowsIdentity.GetCurrent().Impersonate();

        }

        /// <summary>
        /// Resumes impersonation on the thread. When control returns from this method, the
        /// current thread will be running under the identity of the current logon user.
        /// </summary>
        public void ResumeImpersonation()
        {
            if (impersonatedUserIdentity != null)
            {
                impersonatedUserIdentity.Impersonate();
                impersonatedUserIdentity = null;
            }
        }
    }

    internal class Win32API
    {
        [DllImport("advapi32.dll")]
        public static extern bool RevertToSelf();
    }
}
